package com.james.codeauto.util;

import com.james.codeauto.ConvertBridge;
import com.james.codeauto.common.PropertiesComponentWarpper;
import com.james.codeauto.common.StringUtils;
import com.james.codeauto.entity.ClassEntity;
import com.james.codeauto.entity.FieldApiInfo;
import com.james.codeauto.entity.FieldEntity;
import com.james.codeauto.tools.json.JSONArray;
import com.james.codeauto.tools.json.JSONException;
import com.james.codeauto.tools.json.JSONObject;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;


public class GenMarkDownUtils {


    public static List<String> getTemplates() {
        List<String> templates = new ArrayList<String>();
        templates.add("markdown.md.vm");
        return templates;
    }

    public static void main(String[] args) throws Exception {


    }


    public static String getPacesByCount(int count) {
        String space = "";
        for (int i = 0; i < count; i++) {
            space += "&emsp;";
        }
        return space;
    }

    public static Map<String, Object> covertDataEntity(Map<String, Object> map, Map<String, Object> jsonData) throws Exception {
        //配置信息
        Configuration config = getConfig();
        //表信息
        AutoCodeEntity tableEntity = new AutoCodeEntity();
        tableEntity.setComments((String) jsonData.get("desc"));
        tableEntity.setClassName((String) jsonData.get("dtoName"));
        //设置velocity资源加载器
        Properties props = new Properties();
        // props.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        props.put("file.resource.loader.path" , Paths.get("templatevm").toAbsolutePath().toString());
        Velocity.init(props);

        String mainPath = config.getString("mainPath");
        if (map == null) {
            map = new HashMap<>();
        }
        ConvertBridge convertBridge = new ConvertBridge();
        Object jsonObject = jsonData.get("responseJson");
        if (jsonObject != null) {
            JSONObject data = new JSONObject();
            if (jsonObject instanceof JSONArray) {
                data = ((JSONArray) jsonObject).getJSONObject(0);
            } else if (jsonObject instanceof String) {
                return null;
            } else {
                data = (JSONObject) jsonObject;
            }
            if (data == null) {
                return null;
            }
            if (StringUtils.isNotBlank(data.optString("isFirstPage"))) {
                if (data.optJSONArray("list") != null && data.optJSONArray("list").length() > 0) {
                    data = data.optJSONArray("list").optJSONObject(0);
                }
            }
            PropertiesComponentWarpper.useIntellijIdea = false;

            //找出json array
            String arrayKeys = getAllArrayKeys(data);
            if (arrayKeys != null) {

                map.put("hasMoreInnerClass" , true);
                List<Map<String, Object>> innerClassList = new ArrayList<>();
                String[] keys = arrayKeys.split(",");
                for (int i = 0; i < keys.length; i++) {
                    Map<String, Object> itemMap = new HashMap<>();
                    Object info = data.remove(keys[i]);
                    if (info instanceof JSONObject) {
                        JSONObject item = ((JSONArray) data.remove(keys[i])).getJSONObject(0);
                        itemMap.put("name" , keys[i].substring(0, 1).toUpperCase() + keys[i].substring(1));
                        List<FieldEntity> itemFields = convertBridge.createFields(item, (Map<String, FieldApiInfo>) jsonData.get("fieldApiInfo"), convertBridge.collectGenerateFiled(item), new ClassEntity());
                        itemMap.put("columns" , itemFields);
                        innerClassList.add(itemMap);
                    }
                }
                map.put("innerClassList" , innerClassList);
            }

            List<FieldEntity> fields = convertBridge.createFields(data, (Map<String, FieldApiInfo>) jsonData.get("fieldApiInfo"), convertBridge.collectGenerateFiled(data), new ClassEntity());

            map.put("columns" , fields);
        }
        map.put("url" , jsonData.get("url"));
        List<Map<String, Object>> paramList = new ArrayList<>();
        JSONArray jsonArray = (JSONArray) jsonData.get("paramList");
        for (int i = 0; i < jsonArray.length(); i++) {
            Map<String, Object> item = new HashMap<>();
            item.put("realName" , jsonArray.getJSONObject(i).optString("realName"));
            item.put("require" , jsonArray.getJSONObject(i).optString("require"));
            item.put("type" , jsonArray.getJSONObject(i).optString("type"));
            item.put("descMore" , jsonArray.getJSONObject(i).optString("descMore"));
            item.put("desc" , jsonArray.getJSONObject(i).optString("desc"));
            item.put("defaultValue" , jsonArray.getJSONObject(i).optString("defaultValue"));
            item.put("treeNode" , jsonArray.getJSONObject(i).optString("treeNode"));
            item.put("realName",getPacesByCount(Integer.parseInt(String.valueOf(item.get("treeNode"))))+item.get("realName"));
            paramList.add(item);
        }
        map.put("method" , jsonData.get("method"));

        List<Map<String, Object>> param2List = new ArrayList<>();
        JSONArray json2Array = (JSONArray) jsonData.get("responseParamList");
        for (int i = 0; i < json2Array.length(); i++) {
            Map<String, Object> item = new HashMap<>();
            item.put("realName" , json2Array.getJSONObject(i).optString("realName"));
            item.put("require" , json2Array.getJSONObject(i).optString("require"));
            item.put("type" , json2Array.getJSONObject(i).optString("type"));
            item.put("descMore" , json2Array.getJSONObject(i).optString("descMore"));
            item.put("desc" , json2Array.getJSONObject(i).optString("desc"));
            item.put("defaultValue" , json2Array.getJSONObject(i).optString("defaultValue"));
            item.put("treeNode" , json2Array.getJSONObject(i).optString("treeNode"));
            item.put("realName",getPacesByCount(Integer.parseInt(String.valueOf(item.get("treeNode"))))+item.get("realName"));
            param2List.add(item);
        }
        map.put("responseParamList" , param2List);

        map.put("paramList" , paramList);

        map.put("responseParamJsonStr",jsonData.get("responseParamJsonStr"));
        map.put("paramJsonStr",jsonData.get("paramJsonStr"));

        map.put("comments" , tableEntity.getComments());
        map.put("className" , tableEntity.getClassName());
        map.put("classname" , "m" + tableEntity.getClassName());

        map.put("datetime" , format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        VelocityContext context = new VelocityContext(map);
        Map<String, Object> result = new HashMap<>();
        result.put("autoCodeEntity" , tableEntity);
        result.put("context" , context);
        return result;
    }

    public static String format(Date date, String pattern) {
        DateFormat df = createDateFormat(pattern);
        return df.format(date);
    }

    private static DateFormat createDateFormat(String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        TimeZone gmt = TimeZone.getTimeZone("GMT");
        sdf.setTimeZone(gmt);
        sdf.setLenient(true);
        return sdf;
    }

    public static int testIsArrayORObject(String sJSON) {
        /*
         * return 0:既不是array也不是object
         * return 1：是object
         * return 2 ：是Array
         */
        if (sJSON.startsWith("{")) {
            JSONObject object = new JSONObject(sJSON);
            return 1;
        } else if (sJSON.startsWith("[")) {
            JSONArray object = new JSONArray(sJSON);
            return 2;
        } else {
            System.out.println("非法的JSON字符串");
            return 0;
        }

    }

    public static String getAllArrayKeys(JSONObject test) throws JSONException {

        String result = null;

        Iterator keys = test.keys();
        while (keys.hasNext()) {

            try {

                String key = keys.next().toString();
                String value = test.optString(key);

                int i = testIsArrayORObject(value);

                if (i == 2) {

                    result = "," + key;
                    System.out.println("i=2 | key=" + key + "| result=" + result);
//                    JSONArray arrays = new JSONArray(value);
//                    for (int k = 0; k < arrays.length(); k++) {
//                        JSONObject array = new JSONObject(arrays.get(k));
//                        result = getKeys(array) + ",";
//                    }
                }


            } catch (JSONException e) {
                e.printStackTrace();
            }
        }

        if (result != null) {
            result = result.substring(1);
        }

        return result;
    }


    /**
     * 生成代码
     */
    public static String generatorCode(Map<String, Object> jsonData) throws Exception {

        //获取模板列表
        Map<String, Object> data = covertDataEntity(null, jsonData);

        VelocityContext context = (VelocityContext) data.get("context");
        // Configuration config = getConfig();
        List<String> templates = getTemplates();
        //渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(templates.get(0), "UTF-8");
        tpl.merge(context, sw);
        return sw.toString();

    }


    /**
     * 获取配置信息
     */
    public static Configuration getConfig() {

        try {
            PropertiesConfiguration configuration = new PropertiesConfiguration();
            String path = Paths.get("" , "generator.properties").toAbsolutePath().toString();
            configuration.load(new FileInputStream(path));
            return configuration;
        } catch (ConfigurationException | FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 获取文件名
     */
    public static String getFileName(boolean autoCreate, String template, String className, String packageName, String moduleName) {
        String packagePath = "src" + File.separator + "main" + File.separator + "java" + File.separator;
        if (StringUtils.isNotBlank(packageName)) {
            packagePath += packageName.replace("." , File.separator) + File.separator + moduleName + File.separator;
        }

        if (autoCreate) {

            if (template.equals(".java.vm")) {
                return packagePath + "entity" + File.separator + className + ".java";
            }


            if (template.contains("Service.java.vm")) {
                return packagePath + "service" + File.separator + className + "Service.java";
            }

            if (template.contains("ServiceImpl.java.vm")) {
                return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
            }

            if (template.contains("Controller.java.vm")) {
                return packagePath + "controller" + File.separator + className + "Controller.java";
            }
        } else {
            if (template.equals("CouponService.java.vm")) {
                return packagePath + "test" + File.separator + "CouponService.java";
            }

            if (template.equals("Test.java.vm")) {
                return packagePath + "test" + File.separator + className + ".java";
            }

            if (template.equals("TestMap.java.vm")) {
                return packagePath + "test" + File.separator + className + "Map.java";
            }

            if (template.equals("Strage2Map.java.vm")) {
                return packagePath + "test" + File.separator + className + "Strage2Map.java";
            }
            if (template.equals("serviceToMap.java.vm")) {
                return packagePath + "test" + File.separator + className + "serviceToMap.java";
            }

            if (template.contains("TestController.java.vm")) {
                return packagePath + "controller" + File.separator + className + "TestController.java";
            }
        }


        return null;
    }

    private static String splitInnerName(String name) {
        name = name.replaceAll("\\." , "_");
        return name;
    }

    public static String getReturnType(Map<String, Object> jsonData) {
        Object jsonObject = jsonData.get("responseJson");
        String Class = (String) jsonData.get("dtoName");

        int type = 1;// 1 object 2 array  3 page  4 String
        if (jsonObject != null) {
            JSONObject data = new JSONObject();
            if (jsonObject instanceof JSONArray) {
                data = ((JSONArray) jsonObject).getJSONObject(0);
                type = 2;
            } else if (jsonObject instanceof String) {
                type = 4;
            } else {
                data = (JSONObject) jsonObject;
            }
            if (StringUtils.isNotBlank(data.optString("isFirstPage"))) {
                type = 3;
            }
        } else {
            type = 4;
        }
        if (type == 4) { // 1 object 2 array  3 page  4 String
            return "String";
        } else if (type == 3) {
            return "PageResultDto<" + Class + ">";
        } else if (type == 2) {
            return "List<" + Class + ">";
        } else {
            return Class;
        }
    }

    public static void generatorMethodCode(List<Map<String, Object>> iteL) throws Exception {
        if (iteL.isEmpty()) {
            return;
        }
        //获取模板列表
        Map<String, Object> map = new HashMap<>();
        List<Map<String, Object>> methods = new ArrayList<>();
        for (int i = 0; i < iteL.size(); i++) {
            Map<String, Object> item = iteL.get(i);
            Map<String, Object> method = new HashMap<>();
            String url = (String) item.get("url");
            if (url == null) {
                continue;
            }

            String returnType = getReturnType(item);
            method.put("returnType" , returnType);
            if (returnType.startsWith("PageResultDto")) {
                method.put("hasPage" , true);
                method.put("returnType2" , returnType.replaceAll("PageResultDto" , "PageInfoDto"));
            } else {
                method.put("returnType2" , returnType);
            }

            String name = url.substring(item.get("url").toString().lastIndexOf("/") + 1).replace(".do" , "");

            method.put("name" , name);
            method.put("comment" , item.get("title") + " " + item.get("desc"));
            method.put("url" , item.get("url"));
            JSONArray paramList = (JSONArray) item.get("paramList");
            List<Map<String, Object>> paramListArray = new ArrayList<>();
            String paramStr = "";
            String paramStr2 = "";
            String paramStr3 = "";
            HashSet<String> keys = new HashSet<>();
            for (int j = 0; j < paramList.length(); j++) {
                JSONObject param = paramList.getJSONObject(j);
                Map<String, Object> itemParm = new HashMap<>();
                if (param.getString("name").toString().contains(".")) {
                    continue;
                }
                if (param.getString("name").toString().contains("以下是")) {
                    continue;
                }
                if (!keys.add(param.getString("name"))) {
                    continue;
                }

                itemParm.put("name" , param.getString("name"));
                String type = param.getString("type");
                if (type.equals("Int")) {
                    type = "int";
                } else if (type.equals("Timestamp")) {
                    type = "String";
                } else if (type.equals("Intenger")) {
                    type = "Integer";
                } else if (type.equals("bigDecimal") || type.equals("BigDecimal") || type.contains("Bigdecimal")) {
                    type = "String";
                } else if (type.equals("string")) {
                    type = "String";
                }
                itemParm.put("type" , type);
                itemParm.put("require" , param.getString("require"));
                itemParm.put("requireBool" , param.getString("require") == "是" ? true : false);
                itemParm.put("desc" , param.getString("desc"));
                paramListArray.add(itemParm);
                paramStr += ", " + itemParm.get("type") + " " + itemParm.get("name");
                paramStr2 += ", " + itemParm.get("name");
                paramStr3 += ", " + "@RequestParam(\"" + itemParm.get("name") + "\") " + itemParm.get("type") + " " + itemParm.get("name");
            }
            if (paramStr.length() > 0) {
                paramStr = paramStr.substring(1);
            }
            if (paramStr2.length() > 0) {
                paramStr2 = paramStr2.substring(1);
            }
            if (paramStr3.length() > 0) {
                paramStr3 = paramStr3.substring(1);
            }
            method.put("paramStr" , paramStr);
            method.put("paramStr2" , paramStr2);
            method.put("paramStr3" , paramStr3);
            method.put("paramList" , paramListArray);
            method.put("isPost" , "POST".equals(item.get("method")) ? true : false);
            method.put("type" , "POST".equals(item.get("method")) ? "HttpMethod.POST" : "HttpMethod.GET");
            methods.add(method);
        }
        map.put("methods" , methods);
        Map<String, Object> data = covertDataEntity(map, iteL.get(0));

        if (data == null) {

            return;
        }

        AutoCodeEntity tableEntity = (AutoCodeEntity) data.get("autoCodeEntity");
        VelocityContext context = (VelocityContext) data.get("context");
        Configuration config = getConfig();
        List<String> templates = getTemplates();
        for (String template : templates) {
            //渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, sw);
            String fileName = getFileName(false, template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"));
            if (!new File(fileName).exists()) {
                new File(new File(fileName).getParent()).mkdirs();
                new File(fileName).createNewFile();
            }
            try {
                Files.write(Paths.get(fileName), sw.toString().getBytes(StandardCharsets.UTF_8));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
//            try {
//                //添加到zip
//                zip.putNextEntry(new ZipEntry(fileName));
//                IOUtils.write(sw.toString(), zip, "UTF-8");
//                zip.closeEntry();
//            } catch (IOException e) {
//               e.printStackTrace();
//            }
        }
    }
}
